/******************************************************************
*
* Copyright 2010 Darshan M Sonde
*
* This file is part of ddots.
*
* ddots is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ddots is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ddots.  If not, see <http://www.gnu.org/licenses/>.
*
*********************************************************************/

#include "gameapp.h"

GameApp::GameApp(int &argc,char **argv)
    :QApplication(argc,argv),
    mPlayerOneEngine(0),
    mPlayerTwoEngine(0),
    mBoxCompleted(false)
{
    bool b=connect(&mDialog,SIGNAL(accepted()),this,SLOT(newGame()));
    Q_ASSERT(b);
    b=connect(&mDialog,SIGNAL(rejected()),this,SLOT(cancelDialog()));
    Q_ASSERT(b);
    b=connect(this,SIGNAL(engineLoaded(QString)),&mDialog,SLOT(addEngine(QString)));
    Q_ASSERT(b);

    loadPlugins();

    showDialog();
    mScene = mGui.scene();
    b=connect(mScene,SIGNAL(lineSelected(QPoint,QPoint)),this,SLOT(lineComplete(QPoint,QPoint)));
    Q_ASSERT(b);
    
    b=connect(mScene,SIGNAL(boxComplete(QPoint)),this,SLOT(boxCompleteFlagSet()));
    Q_ASSERT(b);

    b=connect(mScene,SIGNAL(showDialog()),this,SLOT(showDialog()));
    Q_ASSERT(b);

    mCurrentTurn = PlayerOne;
}

void GameApp::showDialog()
{    
    mDialog.show();
}

void GameApp::newGame()
{    
    mScene->clearGrid();
    mScene->createGrid(mDialog.rows(),mDialog.columns());
    mScene->setTurn(mCurrentTurn);

    //find the engine choice
    if((!mDialog.playerOneChoice().isEmpty()) && mDialog.playerOneChoice()!="Human") {
        mPlayerOneEngine = mEngines[mDialog.playerOneChoice()];
        mPlayerOneEngine->initGame(mDialog.rows(),mDialog.columns());
    } else {
        mPlayerOneEngine = 0;
    }
    if((!mDialog.playerTwoChoice().isEmpty()) && mDialog.playerTwoChoice()!="Human") {
        mPlayerTwoEngine = mEngines[mDialog.playerTwoChoice()];
        mPlayerTwoEngine->initGame(mDialog.rows(),mDialog.columns());
    } else {
        mPlayerTwoEngine = 0;
    }
    mGui.show();
    updateTurn();
}
void GameApp::cancelDialog()
{
    if(!mGui.isVisible()) {
        qApp->quit();
    }
}

void GameApp::lineComplete(QPoint start, QPoint end)
{
    if(mCurrentTurn==PlayerOne) {
        if(mPlayerTwoEngine) {
            mPlayerTwoEngine->doMove(start.x(),start.y(),end.x(),end.y());
        }
    }
    if(mCurrentTurn==PlayerTwo) {
        if(mPlayerOneEngine) {
            mPlayerOneEngine->doMove(start.x(),start.y(),end.x(),end.y());
        }
    }
    if(!boxCompleted())
        toggleTurn();
    else {
        if(checkGameWon())
            mScene->setWon(true);
        mBoxCompleted=false;
    }
}

void GameApp::toggleTurn()
{    
    if(mCurrentTurn==PlayerOne) {
        mCurrentTurn=PlayerTwo;
    } else {
        mCurrentTurn=PlayerOne;
    }
    mScene->setTurn(mCurrentTurn);
    updateTurn();
}

void GameApp::updateTurn()
{
    if(checkGameWon()) {
        mScene->setWon(true);
        mCurrentTurn = PlayerOne;
        return;
    }
    //this continutes the game and completes/plays the next move.
    mBoxCompleted=false;
    if(mCurrentTurn==PlayerOne)
    {
        if(mPlayerOneEngine)
        {
            int row,col,endrow,endcol;
            if(mPlayerOneEngine->getMove(row,col,endrow,endcol))
            {
                bool b=mScene->selectLine(QPoint(row,col),QPoint(endrow,endcol));
                Q_ASSERT(b);
                if(mPlayerTwoEngine) {
                        mPlayerTwoEngine->doMove(row,col,endrow,endcol);
                }

                if(!boxCompleted())
                {
                    QTimer::singleShot(DELAY,this,SLOT(toggleTurn()));
                }
                else
                {
                    QTimer::singleShot(DELAY,this,SLOT(updateTurn()));
                }
            }
        }
    } else {
        if(mPlayerTwoEngine)
        {
            int row,col,endrow,endcol;
            if(mPlayerTwoEngine->getMove(row,col,endrow,endcol))
            {
                bool b=mScene->selectLine(QPoint(row,col),QPoint(endrow,endcol));
                Q_ASSERT(b);
                if(mPlayerOneEngine) {
                        mPlayerOneEngine->doMove(row,col,endrow,endcol);
                }

                if(!boxCompleted())
                {
                    QTimer::singleShot(DELAY,this,SLOT(toggleTurn()));
                }
                else
                {
                    QTimer::singleShot(DELAY,this,SLOT(updateTurn()));
                }
            }
        }
    }
}

void GameApp::boxCompleteFlagSet()
{
    mBoxCompleted=true;
}

bool GameApp::boxCompleted()
{//returns if boxWasCompleted last.
    return mBoxCompleted;
}

bool GameApp::checkGameWon()
{
    int boxesCompleted = mScene->playerScore(PlayerOne)+mScene->playerScore(PlayerTwo);
    int maxBoxes = (mDialog.rows()-1)*(mDialog.columns()-1);
    Q_ASSERT(maxBoxes>0);
    return (boxesCompleted==maxBoxes);
}

void GameApp::loadPlugins()
{
    QDir pluginDir = QDir(qApp->applicationDirPath());
    pluginDir.cd("plugins");
    foreach(QString fileName,pluginDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginDir.absoluteFilePath(fileName));
        QObject *plugin=loader.instance();
        if(plugin) {
            EngineInterface *engine=qobject_cast<EngineInterface*>(plugin);
            if(engine && !mEngines.contains(engine->name())) {
                mEngines.insert(engine->name(),engine);                
                emit engineLoaded(engine->name());                                
            }
        }
    }
}
